package com.example.micinter_ipcamera;

import fi.iki.elonen.NanoHTTPD;

import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;

public class IpCameraServer extends NanoHTTPD {

    public static final int DEFAULT_PORT = 8080;
    private static final String BOUNDARY = "--frame";

    private final AtomicReference<byte[]> latestJpeg;

    public IpCameraServer(int port, AtomicReference<byte[]> latestJpeg) {
        super(port);
        this.latestJpeg = latestJpeg;
    }

    @Override
    public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
        String uri = session.getUri();
        if ("/mjpeg".equals(uri)) {
            return createMjpegStream();
        }
        return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.OK, "text/html; charset=utf-8", buildIndexHtml());
    }

    private String buildIndexHtml() {
        return "<!doctype html>" +
                "<html><head><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">" +
                "<title>Android IP Camera</title></head>" +
                "<body style=\"margin:0;background:#111;color:#eee;font-family:system-ui,sans-serif\">" +
                "<div style=\"padding:12px\"><h2 style=\"margin:0 0 8px\">Android IP Camera</h2>" +
                "<p>MJPEG stream:</p></div>" +
                "<img src=\"/mjpeg\" style=\"width:100%;height:auto;display:block\"/>" +
                "</body></html>";
    }

    private NanoHTTPD.Response createMjpegStream() {
        try {
            final PipedOutputStream pipedOut = new PipedOutputStream();
            // 增大缓冲区到256KB，减少阻塞
            final InputStream pipedIn = new PipedInputStream(pipedOut, 256 * 1024);

            Thread writer = new Thread(() -> {
                byte[] localLast = null;
                long lastFrameTime = 0;
                final long TARGET_FPS = 15; // 目标帧率15fps，约67ms间隔
                final long FRAME_INTERVAL_MS = 1000 / TARGET_FPS;
                try {
                    while (!Thread.currentThread().isInterrupted()) {
                        byte[] jpeg = latestJpeg.get();
                        long currentTime = System.currentTimeMillis();
                        
                        // 如果有新帧且距离上一帧时间足够，立即发送
                        if (jpeg != null && jpeg != localLast) {
                            if (currentTime - lastFrameTime >= FRAME_INTERVAL_MS) {
                                localLast = jpeg;
                                writeFrame(pipedOut, jpeg);
                                lastFrameTime = currentTime;
                            }
                        }
                        
                        // 使用更短的睡眠时间以减少延迟
                        try { 
                            Thread.sleep(5); // 从10ms减少到5ms，提高响应速度
                        } catch (InterruptedException e) { 
                            Thread.currentThread().interrupt(); 
                        }
                    }
                } finally {
                    try { pipedOut.close(); } catch (IOException ignored) { }
                }
            }, "MJPEG-Writer");
            writer.setDaemon(true);
            writer.start();

            String mime = "multipart/x-mixed-replace; boundary=" + BOUNDARY;
            return NanoHTTPD.newChunkedResponse(NanoHTTPD.Response.Status.OK, mime, pipedIn);
        } catch (IOException e) {
            return NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.INTERNAL_ERROR, "text/plain", "MJPEG error");
        }
    }

    private void writeFrame(PipedOutputStream out, byte[] jpeg) {
        try {
            String header = "--" + BOUNDARY + "\r\n" +
                    "Content-Type: image/jpeg\r\n" +
                    "Content-Length: " + jpeg.length + "\r\n\r\n";
            out.write(header.getBytes(StandardCharsets.US_ASCII));
            out.write(jpeg);
            out.write("\r\n".getBytes(StandardCharsets.US_ASCII));
            out.flush();
        } catch (IOException ignored) {
        }
    }
}


